package com.shy.base.aop;

import java.lang.reflect.Method;

import javax.annotation.Resource;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;

import lombok.extern.slf4j.Slf4j;

/**
 * 日志切面
 * <p>Title:LogAspect </p>
 * <p>Description: </p>
 * <p>Company:ipebg </p> 
 * @author H2013788
 * @date 2019年7月12日
 */
@Slf4j
@Aspect
@Component
public class LogAspect {

	/**
     * 日志切入点
     */
	@Resource
    private LogPoint logPoint;
	
    
	@Pointcut("@annotation(com.shy.base.aop.LogAnnotation)")
    private void accAspect() {}

    

    /**
     * 保存系统操作日志
     *
     * @param joinPoint 连接点
     * @return 方法执行结果
     * @throws Throwable 调用出错
     */
    @After("accAspect()")
    public void save(JoinPoint joinPoint) throws Throwable {
        /**
         * 解析Log注解
         */
        String methodName = joinPoint.getSignature().getName();
        Method method = currentMethod(joinPoint, methodName);
        LogAnnotation log = method.getAnnotation(LogAnnotation.class);

        /**
         * 日志入库
         */
        if (log != null) {
            logPoint.save(joinPoint, methodName, log.module(), log.description());
        }
    }
    
    
    /**
     * 【@Around注解可以用来在调用一个具体方法前和调用后来完成一些具体的任务】
     * 比如我们想在执行controller中方法前打印出请求参数，
     * 并在方法执行结束后来打印出响应值，这个时候，我们就可以借助于@Around注解来实现；
     * 此方法更進一步展現@Around註解的特點
     * @param joinPoint
     * @return
     * @throws Throwable
     * @author H2013788
     * @date 2020年8月11日
     */
    public Object run1(ProceedingJoinPoint joinPoint) throws Throwable {
        //获取方法参数值数组
        Object[] args = joinPoint.getArgs();
        log.info("请求参数为{}",args);
        //动态修改其参数
        //注意，如果调用joinPoint.proceed()方法，则修改的参数值不会生效，必须调用joinPoint.proceed(Object[] args)
        Object result = joinPoint.proceed(args);
        log.info("响应结果为{}",result);
        //如果这里不返回result，则目标对象实际返回值会被置为null
        return result;
    }
    
    

    /**
     * 获取当前执行的方法
     *
     * @param joinPoint  连接点
     * @param methodName 方法名称
     * @return 方法
     */
    private Method currentMethod(JoinPoint joinPoint, String methodName) {
        /**
         * 获取目标类的所有方法，找到当前要执行的方法
         */
        Method[] methods = joinPoint.getTarget().getClass().getMethods();
        Method resultMethod = null;
        for (Method method : methods) {
            if (method.getName().equals(methodName)) {
                resultMethod = method;
                break;
            }
        }
        return resultMethod;
    }
    

}

